<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
  <meta charset="UTF-8">
  <title>Keymaps In-Depth</title>
  <link data-turbolinks-track="true" href="../../../assets/application-b86a2086c99917c6bf2a9d74b4038381.css" media="all" rel="stylesheet" />
  <script data-turbolinks-track="true" src="../../../assets/application-c3106c6fe52ccec6f26495730a478cca.js"></script>
  <meta content="authenticity_token" name="csrf-param" />
<meta content="yzXUiWH6GiCHbvbJOg7usjzA7LawyxwB+oJHEcWTOIM=" name="csrf-token" />
  <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-3769691-35', 'atom.io');
  ga('send', 'pageview');

</script>

  <meta property="og:url" content="https://atom.io/" />
<meta property="og:site_name" content="Atom" />
<meta property="og:title" content="A hackable text editor for the 21st Century" />
<meta property="og:description" content="At GitHub, we’re building the text editor we’ve always wanted: hackable to the core, but approachable on the first day without ever touching a config file. We can’t wait to see what you build with it." />
<meta property="og:type" content="website" />
<meta property="og:author" content='https://www.facebook.com/GitHub' />
<meta property="og:image" content="http://og.github.com/atom-logo/atom-logo@1200x1200.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="1200" />
<meta property="og:image" content="http://og.github.com/atom-mark/atom-mark@1200x630.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

  <meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:site" content="@AtomEditor" />
<meta property="twitter:creator" content='@github' />
<meta property="twitter:title" content="Atom" />
<meta property="twitter:description" content="A hackable text editor for the 21st Century" />
<meta property="twitter:image:src" content="http://og.github.com/atom-logo/atom-logo@1200x630.png" />
<meta property="twitter:image:width" content="1200" />
<meta property="twitter:image:height" content="630" />

  <link rel="shortcut icon" href="../../../favicon.ico"/>
</head>
<body>

  <div class="footer-push">
    
    

    <header class="header">
  <div class="wrapper">
    <h1 title="Atom">
      <a href="../../../index.html" class="logo"></a>
    </h1>

    <ul class="navigation">
      <li><a class="" href="../../../packages.html">Packages</a></li>
      <li><a class="is-selected" href="../../latest/index.html">Documentation</a></li>
      <li><a href="http://blog.atom.io">Blog</a></li>
      <li><a href="../../../faq.html">FAQ</a></li>
      <li><a class="" href="https://atom.io/contact">Contact</a></li>
    </ul>
  </div>
</header>


    <div class="wrapper documents content-push">
  <div class="columns">
    <div class="column main-column markdown">
        <h1>
<a name="keymaps-in-depth" href="keymaps.html#keymaps-in-depth"></a>Keymaps In-Depth</h1>

<h2>
<a name="structure-of-a-keymap-file" href="keymaps.html#structure-of-a-keymap-file"></a>Structure of a Keymap File</h2>

<p>Keymap files are encoded as JSON or CSON files containing nested hashes. They
work much like stylesheets, but instead of applying style properties to elements
matching the selector, they specify the meaning of keystrokes on elements
matching the selector. Here is an example of some bindings that apply when
keystrokes pass through elements with the class <code>.editor</code>:</p>

<pre lang="coffee"><div class="line"><span class="source coffee"><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>.editor</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>cmd-delete</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:backspace-to-beginning-of-line</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>alt-backspace</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:backspace-to-beginning-of-word</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>ctrl-A</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:select-to-first-character-of-line</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>ctrl-shift-e</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:select-to-end-of-line</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>cmd-left</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:move-to-first-character-of-line</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span> </span></span></div><div class="line"><span class="source coffee"><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>.editor:not(.mini)</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>cmd-alt-[</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:fold-current-row</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>cmd-alt-]</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:unfold-current-row</span><span class="punctuation definition string end coffee"><span>'</span></span></span></span></div></pre>

<p>Beneath the first selector are several bindings, mapping specific <em>keystroke
patterns</em> to <em>commands</em>. When an element with the <code>.editor</code> class is focused and
<code>cmd-delete</code> is pressed, an custom DOM event called
<code>editor:backspace-to-beginning-of-line</code> is emitted on the <code>.editor</code> element.</p>

<p>The second selector group also targets editors, but only if they don't have the
<code>.mini</code> class. In this example, the commands for code folding don't really make
sense on mini-editors, so the selector restricts them to regular editors.</p>

<h3>
<a name="keystroke-patterns" href="keymaps.html#keystroke-patterns"></a>Keystroke Patterns</h3>

<p>Keystroke patterns express one or more keystrokes combined with optional
modifier keys. For example: <code>ctrl-w v</code>, or <code>cmd-shift-up</code>. A keystroke is
composed of the following symbols, separated by a <code>-</code>. A multi-keystroke pattern
can be expressed as keystroke patterns separated by spaces.</p>

<table>
<thead><tr>
<th>Type</th>
<th>Examples</th>
</tr></thead>
<tbody>
<tr>
<td>Character literals</td>
<td>
<code>a</code> <code>4</code> <code>$</code>
</td>
</tr>
<tr>
<td>Modifier keys</td>
<td>
<code>cmd</code> <code>ctrl</code> <code>alt</code> <code>shift</code>
</td>
</tr>
<tr>
<td>Special keys</td>
<td>
<code>enter</code> <code>escape</code> <code>backspace</code> <code>delete</code> <code>tab</code> <code>home</code> <code>end</code> <code>pageup</code> <code>pagedown</code> <code>left</code> <code>right</code> <code>up</code> <code>down</code>
</td>
</tr>
</tbody>
</table><h3>
<a name="commands" href="keymaps.html#commands"></a>Commands</h3>

<p>Commands are custom DOM events that are triggered when a keystroke matches a
binding. This allows user interface code to listen for named commands without
specifying the specific keybinding that triggers it. For example, the following
code sets up {EditorView} to listen for commands to move the cursor to the first
character of the current line:</p>

<pre lang="coffee"><div class="line"><span class="source coffee"><span class="meta class coffee"><span class="storage type class coffee"><span>class</span></span><span> </span><span class="entity name type class coffee"><span>EditorView</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="meta function coffee"><span class="entity name function coffee"><span>listenForEvent</span><span class="entity name function coffee"><span>s</span></span></span></span><span class="keyword operator coffee"><span>:</span></span><span> </span><span class="storage type function coffee"><span>-&gt;</span></span></span></div><div class="line"><span class="source coffee"><span>    </span><span class="variable other readwrite instance coffee"><span>@command</span></span><span> </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>editor:move-to-first-character-of-line</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="meta delimiter object comma coffee"><span>, </span></span><span class="storage type function coffee"><span>=&gt;</span></span></span></div><div class="line"><span class="source coffee"><span>      </span><span class="variable other readwrite instance coffee"><span>@editor</span></span><span class="meta delimiter method period coffee"><span>.</span></span><span>moveCursorToFirstCharacterOfLine</span><span class="meta brace round coffee"><span>(</span><span>)</span></span></span></div></pre>

<p>The <code>::command</code> method is basically an enhanced version of jQuery's <code>::on</code>
method that listens for a custom DOM event and adds some metadata to the DOM,
which is read by the command palette.</p>

<p>When you are looking to bind new keys, it is often useful to use the command
palette (<code>ctrl-shift-p</code>) to discover what commands are being listened for in a
given focus context. Commands are "humanized" following a simple algorithm, so a
command like <code>editor:fold-current-row</code> would appear as "Editor: Fold Current
Row".</p>

<h3>
<a name="specificity-and-cascade-order" href="keymaps.html#specificity-and-cascade-order"></a>Specificity and Cascade Order</h3>

<p>As is the case with CSS applying styles, when multiple bindings match for a
single element, the conflict is resolved by choosing the most <em>specific</em>
selector. If two matching selectors have the same specificity, the binding
for the selector appearing later in the cascade takes precedence.</p>

<p>Currently, there's no way to specify selector ordering within a single keymap,
because JSON objects do not preserve order. We eventually plan to introduce a
custom CSS-like file format for keymaps that allows for ordering within a single
file. For now, we've opted to handle cases where selector ordering is critical
by breaking the keymap into two separate files, such as <code>snippets-1.cson</code> and
<code>snippets-2.cson</code>.</p>

<h2>
<a name="overloading-key-bindings" href="keymaps.html#overloading-key-bindings"></a>Overloading Key Bindings</h2>

<p>Occasionally, it makes sense to layer multiple actions on top of the same key
binding. An example of this is the snippets package. Snippets are inserted by
typing a snippet prefix such as <code>for</code> and then pressing <code>tab</code>. Every time <code>tab</code>
is pressed, we want to execute code attempting to expand a snippet if one exists
for the text preceding the cursor. If a snippet <em>doesn't</em> exist, we want <code>tab</code>
to actually insert whitespace.</p>

<p>To achieve this, the snippets package makes use of the <code>.abortKeyBinding()</code>
method on the event object representing the <code>snippets:expand</code> command.</p>

<pre lang="coffee-script"><div class="line"><span class="source coffee"><span class="comment line number-sign coffee"><span class="punctuation definition comment coffee"><span>#</span></span><span> pseudo-code</span></span></span></div><div class="line"><span class="source coffee"><span>editor</span><span class="meta delimiter method period coffee"><span>.</span></span><span>command </span><span class="string quoted single coffee"><span class="punctuation definition string begin coffee"><span>'</span></span><span>snippets:expand</span><span class="punctuation definition string end coffee"><span>'</span></span></span><span class="meta delimiter object comma coffee"><span>, </span></span><span class="meta inline function coffee"><span class="variable parameter function coffee"><span>(e)</span></span><span> </span><span class="storage type function coffee"><span>=&gt;</span></span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="keyword control coffee"><span>if</span></span><span> </span><span class="variable other readwrite instance coffee"><span>@cursorFollowsValidPrefix</span></span><span class="meta brace round coffee"><span>(</span><span>)</span></span></span></div><div class="line"><span class="source coffee"><span>    </span><span class="variable other readwrite instance coffee"><span>@expandSnippet</span></span><span class="meta brace round coffee"><span>(</span><span>)</span></span></span></div><div class="line"><span class="source coffee"><span>  </span><span class="keyword control coffee"><span>else</span></span></span></div><div class="line"><span class="source coffee"><span>    e</span><span class="meta delimiter method period coffee"><span>.</span></span><span>abortKeyBinding</span><span class="meta brace round coffee"><span>(</span><span>)</span></span></span></div></pre>

<p>When the event handler observes that the cursor does not follow a valid prefix,
it calls <code>e.abortKeyBinding()</code>, telling the keymap system to continue searching
for another matching binding.</p>

<h2>
<a name="step-by-step-how-keydown-events-are-mapped-to-commands" href="keymaps.html#step-by-step-how-keydown-events-are-mapped-to-commands"></a>Step-by-Step: How Keydown Events are Mapped to Commands</h2>

<ul>
<li>A keydown event occurs on a <em>focused</em> element.</li>
<li>Starting at the focused element, the keymap walks upward towards the root of
the document, searching for the most specific CSS selector that matches the
current DOM element and also contains a keystroke pattern matching the keydown
event.</li>
<li>When a matching keystroke pattern is found, the search is terminated and the
pattern's corresponding command is triggered on the current element.</li>
<li>If <code>.abortKeyBinding()</code> is called on the triggered event object, the search
is resumed, triggering a binding on the next-most-specific CSS selector for
the same element or continuing upward to parent elements.</li>
<li>If no bindings are found, the event is handled by Chromium normally.</li>
</ul>
    </div>
    <div class="column sidebar documents-toc">
      <select class="js-doc-version-switcher version-switcher">
  <option value="v0.69.0">v0.69.0</option>
<option value="v0.68.0">v0.68.0</option>
<option value="v0.67.0">v0.67.0</option>
<option value="v0.66.0">v0.66.0</option>
<option value="v0.65.0">v0.65.0</option>
<option value="v0.64.0">v0.64.0</option>
<option value="v0.63.0">v0.63.0</option>
<option value="v0.62.0">v0.62.0</option>
<option selected="selected" value="v0.61.0">v0.61.0</option>
<option value="v0.60.0">v0.60.0</option>
<option value="v0.59.0">v0.59.0</option>
<option value="v0.58.0">v0.58.0</option>
<option value="v0.57.0">v0.57.0</option>
<option value="v0.56.0">v0.56.0</option>
<option value="v0.55.0">v0.55.0</option>
<option value="v0.54.0">v0.54.0</option>
<option value="v0.53.0">v0.53.0</option>
<option value="v0.51.0">v0.51.0</option>
<option value="v0.50.0">v0.50.0</option>
<option value="v0.49.0">v0.49.0</option>
<option value="v0.48.0">v0.48.0</option>
<option value="v0.47.0">v0.47.0</option>
<option value="v0.46.0">v0.46.0</option>
<option value="v0.45.0">v0.45.0</option>
<option value="v0.44.0">v0.44.0</option>
<option value="v0.41.0">v0.41.0</option>
<option value="v0.40.0">v0.40.0</option>
<option value="0.52.0">0.52.0</option>
</select>


      <ul class="navigation">
        <li><a href="" class="is-selected">Documentation</a></li>
        <li><a href="../../api/v0.61.0/api/index.html">API</a></li>
      </ul>

      <hr />

      <form accept-charset="UTF-8" action="/docs/v0.61.0/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
        <input class="sidebar-search-field" id="q" name="q" placeholder="Search documentation" type="text" value="" />
</form>
      <h2>
<a name="guides" href="keymaps.html#guides"></a>Guides</h2>

<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../customizing-atom.html">Customizing Atom</a></li>
<li><a href="../creating-a-package.html">Creating a Package</a></li>
<li><a href="../creating-a-theme.html">Creating a Theme</a></li>
<li><a href="../publishing-a-package.html">Publishing a Package</a></li>
<li><a href="../converting-a-text-mate-bundle.html">Converting a TextMate Bundle</a></li>
<li><a href="../converting-a-text-mate-theme.html">Converting a TextMate Theme</a></li>
<li><a href="../contributing.html">Contributing</a></li>
</ul><h3>
<a name="advanced-topics" href="keymaps.html#advanced-topics"></a>Advanced Topics</h3>

<ul>
<li><a href="configuration.html">Configuration</a></li>
<li><a href="keymaps.html">Keymaps</a></li>
<li><a href="serialization.html">Serialization</a></li>
<li><a href="view-system.html">View System</a></li>
</ul>
    </div>
  </div>
</div>


    <div class="footer-pad"></div>
  </div>

  <footer>
  <div class="footer">
    <div class="wrapper">
      <ul class="footer-left">
        <li><a href="../../../terms.html">Terms of Use</a></li>
          <li><a href="https://atom.io/login">Sign in</a></li>
      </ul>

      <div class="footer-right">
        <a href="https://github.com"><span class="octicon octicon-code"></span> with <span class="octicon octicon-heart"></span> by <span class="octicon octicon-logo-github"></span></a>
      </div>
    </div>
  </div>
</footer>

</body>
</html>
